/**
 * create by young (young2f@outlook.com) on 2023/4/16
 */
'use strict';
const base = require('../base/serviceBase');
const _ = require('lodash');
const _stringUtils = require('../utils/stringUtils');
const table = 'ProcureOrder';
const moment = require('moment');
const { result } = require('lodash');
const { getTax } = require('../base/serviceBase');

module.exports = class extends base {
  async editOld(body) {
    const { ctx } = this;
    // const result = await ctx.app.dbs.find('Customer', {});
    // _.map(result, async item => {
    //   let { contactsPhone, contacts, address, contactList, code } = item;
    //   if (!contactList) {
    //     contactList = [];
    //     contactList.push({ contacts, contactsPhone, address, code: new Date().valueOf() });
    //   }
    //
    //   const result = await ctx.app.dbs.updateOne('Customer', { code }, { contactList });
    //   console.log('ress', result);
    // });

    // const result = await ctx.app.dbs.find('ProcureOrder', {});
    // _.map(result, async item => {
    //   let { materials, material, materialCode, spec, type, materialNumber, materialBody, count, price, code } = item;
    //   if (!materials) {
    //     materials = [];
    //     materialBody.price = price;
    //     materialBody.count = count;
    //     materials.push(materialBody);
    //   }
    //
    //   const result = await ctx.app.dbs.updateOne('ProcureOrder', { code }, { materials, count, amount: count * price });
    //   console.log('ress', result);
    // });

    return { status: 'ok', result };
  }

  /**
   * 创建采购单
   * 生成入库单、验收单、付款申请单（不需要，直接获取采购物料记录）
   * @param body
   * @returns {Promise<{status: string, result: *}|{status: string, result: *}>}
   */
  async create(body) {
    const { ctx, service } = this;
    // const { price = 0, count = 0 } = body;
    // body.amount = price * count;
    console.log('create procure', body);
    const { vendorCode, vendor, tenantCode, tenantName, division, amount = 0, taxRate } = body;
    body.tax = this.getTax(amount, taxRate);

    /**
     * 如果供应商是录入的，不是选择的，就新建一个供应商
     */
    if (!vendorCode) {
      const vCode = _stringUtils.getCode('VEN');
      body.vendorCode = vCode;
      const result = await ctx.app.dbs.insert('Vendor', {
        name: vendor,
        code: vCode,
        tenantCode,
        tenantName,
        division
      });
    }
    /**
     * 创建采购物料记录
     */
    if (!body.materials) body.materials = [];
    const { materials = [] } = body;
    _.map(materials, async item => {
      const res = await this.createProcureMaterialRecord(body, item);
    });
    /**
     * 创建运费
     * @type {boolean}
     */
    const res1 = await this.createOrUpdateShippingFee(body);

    const result = await ctx.app.dbs.insert(table, body);
    return { status: 'ok', result };
    //return await this.createInboundOrder(body);
  }

  async createProcureMaterialRecord(body, item) {
    const { ctx } = this;
    const { key, vendor, vendorCode, createdTs, division, isRent, reviewStatus, acceptanceStatus, materialType } = body;
    item.procureOrderCode = body.code;
    item.vendor = vendor;
    item.vendorCode = vendorCode;
    item.isRent = isRent;
    item.useCount = 0;
    item.acceptanceStatus = acceptanceStatus;
    item.materialType = materialType;
    item.reviewStatus = reviewStatus;
    //item.usedCount = item.count;//可用数量
    item.division = division;

    const { price = 0, count, code } = item;
    item.price = price;
    delete item._id;
    delete item.createdAt;
    delete item.createdTs;
    console.log('createProcureMaterialRecord', item);
    /**
     * 更新物料可用数量
     * @type {*|void}
     */
    const res1 = await this.updateMaterialProcureCount(item);
    /**
     * 创建批准
     */
    return await ctx.app.dbs.insert('ProcureMaterialRecord', item);
  }

  /**
   * 更新物料的可用数量
   * @returns {Promise<void>}
   * @param tenantCode
   * @param code
   * @param count
   */
  async updateMaterialProcureCount({ tenantCode, code, count }) {
    const { ctx } = this;
    // /**
    //  * 更新物料的在途数量
    //  */
    const res = await ctx.app.dbs.updateOne('Material', { code, tenantCode }, { $inc: { 'procureCount': count } });
  }

  /**
   * 修改采购单
   * 物料进行两次对比
   * @param body
   * @returns {Promise<{status: string, result: *}>}
   */
  async updateOne(body) {
    const { tenantCode, code, materials = [], amount, taxRate } = body;
    body.tax = this.getTax(amount, taxRate);

    const { ctx } = this;
    const oldMaterials = await ctx.app.dbs.find('ProcureMaterialRecord', { procureOrderCode: code, tenantCode });
    console.log('updateOne Materials', body);
    /**
     * 物料采购批次：查找这个采购单所有的采购物料批次，先删除，再创建
     * 如果原批次没有，就创建
     */
    /**
     * 先删除
     */
    const deleteRes = await ctx.app.dbs.deleteMany('ProcureMaterialRecord', { procureOrderCode: code, tenantCode });
    /**
     * 减少原料的可用数量
     * @type {boolean}
     */
    _.map(oldMaterials, async item => {
      const { count } = item;
      item.count = -count;
      const res1 = deleteRes && await this.updateMaterialProcureCount(item);
    });
    /**
     * 再创建
     */
    _.map(materials, async item => {
      const res = await this.createProcureMaterialRecord(body, item);
    });

    const res1 = await this.createOrUpdateShippingFee(body);
    const result = await ctx.app.dbs.updateOne(table, { tenantCode, code }, body);
    return { status: 'ok', result };
  }


  async deleteOne(body) {
    console.log('deleteOne', body);
    const { tenantCode, code } = body;
    const { ctx } = this;
    const order = await ctx.app.dbs.findOne(table, { tenantCode, code });

    // if (procureMaterialRecords && procureMaterialRecords.length) {
    //   throw new Error('采购单的物料已被订单占用，请先修改订单后再删除！');
    // }
    if (order.reviewStatus === '同意') {
      throw new Error('删除失败！采购单已审核通过！');
    }
    const inboundLots = await ctx.app.dbs.find('InboundLot', { procureOrderCode: code, tenantCode });
    if (inboundLots && inboundLots.length > 0) {
      throw new Error('删除失败！采购单已有入库记录，请删除入库记录后再执行采购单删除！');
    }
    const payRecords = await ctx.app.dbs.find('Payment', { orderCode: code, tenantCode });
    if (payRecords && payRecords.length > 0) {
      throw new Error('删除失败！采购单已有付款记录，请删除付款记录后再执行采购单删除！');
    }
    const shippingFee = await ctx.app.dbs.find('Payment', {
      orderCode: code,
      tenantCode,
      payType: '运费'
    },);
    if (shippingFee && shippingFee.length > 0) {
      throw new Error('删除失败！采购单已有运费付款记录，请删除运费付款记录后再执行采购单删除！');
    }
    /**
     * 修改物料可用数量
     */
    const procureMaterialRecords = await ctx.app.dbs.find('ProcureMaterialRecord', {
      tenantCode,
      procureOrderCode: code,
      // useCount: { '$gt': 0 }
    });
    console.log('procureMaterialRecords', procureMaterialRecords);
    _.map(procureMaterialRecords, async item => {
      const { count } = item;
      item.count = -count;
      console.log('xxxxx', item);
      const resUp = await this.updateMaterialProcureCount(item);
    });
    /**
     * 删除物料采购记录
     */
    const result0 = await ctx.app.dbs.deleteMany('ProcureMaterialRecord', { procureOrderCode: code });

    const result1 = await ctx.app.dbs.deleteMany('ShippingFee', { orderCode: code });

    const result = await ctx.app.dbs.deleteOne(table, { tenantCode, code });

    return { status: 'ok', result };
  }


  async findMany(body) {
    const { ctx } = this;
    const { key, vendor, code, createdTs, isRent, reviewStatus, acceptanceStatus, materialType } = body;
    const _key = key ? key : 'createdTs';
    if (createdTs && createdTs.length > 0) {
      body['createdTs'] = {
        $gte: new Date(moment(createdTs[0])
          .valueOf()),
        $lt: new Date(moment(createdTs[1])
          .valueOf())
      };
    }

    const sort = {};
    sort[_key] = -1;
    if (vendor) body['vendor'] = { $regex: vendor };
    if (code) body['code'] = { $regex: code };
    if (acceptanceStatus) body['acceptanceStatus'] = { $regex: acceptanceStatus };
    if (reviewStatus) body['reviewStatus'] = { $regex: reviewStatus };
    if (materialType) body['materialType'] = { $regex: materialType };
    if (isRent) body['isRent'] = isRent;
    const result = await ctx.app.dbs.aggregate(table, [
      { $match: { ...body } },
      { $sort: { ...sort } },
    ]);
    return { status: 'ok', result };
  }

  async findStatistic(body) {
    const { ctx } = this;
    //  console.log('find procure', body);
    const { key, vendor, code, createdTs, isRent, reviewStatus, acceptanceStatus, materialType } = body;
    const _key = key ? key : 'createdTs';
    if (createdTs && createdTs.length > 0) {
      body['createdTs'] = {
        $gte: new Date(moment(createdTs[0])
          .valueOf()),
        $lt: new Date(moment(createdTs[1])
          .valueOf())
      };
    }

    const sort = {};
    sort[_key] = -1;
    if (vendor) body['vendor'] = { $regex: vendor };
    if (code) body['procureOrderCode'] = { $regex: code };
    if (acceptanceStatus) body['acceptanceStatus'] = { $regex: acceptanceStatus };
    if (reviewStatus) body['reviewStatus'] = { $regex: reviewStatus };
    if (materialType) body['materialType'] = { $regex: materialType };
    if (isRent) body['isRent'] = isRent;
    delete body.code;
    const orders = await ctx.app.dbs.aggregate('ProcureMaterialRecord', [
      { $match: { ...body } },
      { $sort: { ...sort } },
    ]);

    let amount = 0,
      count = 0;
    _.map(orders, item => {
      const { reviewStatus } = item;
      //if (reviewStatus !== '驳回') {
      const { price = 0 } = item;
      amount += price * item.count;
      count += item.count;
      // }
    });
    const result = { amount, count, orders };
    return { status: 'ok', result };
  }

  async findOne(body) {
    const { tenantCode, code } = body;
    const { ctx } = this;
    const result = await ctx.app.dbs.findOne(table, { tenantCode, code });
    return { status: 'ok', result };
  }


  async review(body) {
    const { ctx } = this;
    console.log('审核采购单', body);
    const { tenantCode, code, reviewStatus, acceptanceStatus, } = body;
    if (reviewStatus !== undefined) {
      const result = await ctx.app.dbs.updateOne(table, { tenantCode, code }, { reviewStatus });
      const result1 = await ctx.app.dbs.updateMany('ProcureMaterialRecord', {
        tenantCode,
        procureOrderCode: code
      }, { reviewStatus });
      console.log('审核采购单结果', result);
      return { status: 'ok', result };
    }
    if (acceptanceStatus !== undefined) {
      const result = await ctx.app.dbs.updateOne(table, { tenantCode, code }, { acceptanceStatus });
      const result1 = await ctx.app.dbs.updateMany('ProcureMaterialRecord', {
        tenantCode,
        procureOrderCode: code
      }, { acceptanceStatus });
      console.log('更新验收状态', acceptanceStatus);
      return { status: 'ok', result };
    }
    return { status: 'ok' };
  }

  async createReturnGoodsOrder(body) {
    const { ctx } = this;
    delete body['createdTs'];
    delete body['_id'];
    const result = await ctx.app.dbs.insert('ProcureMaterialReturnOrder', body);
    return { status: 'ok', result };
  }

  async deleteReturnGoodsOrder(body) {
    const { ctx } = this;

    const { orderCode, tenantCode } = body;
    const result = await ctx.app.dbs.deleteOne('ProcureMaterialReturnOrder', { orderCode, tenantCode });
    return { status: 'ok', result };
  }

  async updateReturnGoodsOrder(body) {
    const { ctx } = this;
    const { orderCode, tenantCode } = body;
    const result = await ctx.app.dbs.updateOne('ProcureMaterialReturnOrder', {
      orderCode,
      tenantCode
    }, body);
    return { status: 'ok', result };
  }

  async findReturnOrderMany(body) {
    const { ctx } = this;
    const { key, vendor, code, name, tenantCode, createdTs } = body;
    const query = { tenantCode };
    const _key = key ? key : 'createdTs';
    if (createdTs && createdTs.length > 0) {
      query['createdTs'] = {
        $gte: new Date(moment(createdTs[0])
          .valueOf()),
        $lt: new Date(moment(createdTs[1])
          .valueOf())
      };
    }

    const sort = {};
    sort[_key] = -1;

    if (vendor) query['vendor'] = { $regex: vendor };
    if (code) query['code'] = { $regex: code };
    if (name) query['name'] = { $regex: name };

    const list = await ctx.app.dbs.find('ProcureMaterialReturnOrder', query);
    const countRes = await this.app.dbs.aggregate('ProcureMaterialReturnOrder', [
      { $match: { ...query } },
      { $group: { _id: null, count: { $sum: '$returnCount' } } },

    ]);
    const assessRes = await this.app.dbs.aggregate('ProcureMaterialReturnOrder', [
      { $match: { ...query } },
      {
        $project: {
          totalPrice: { $multiply: [ '$returnCount', '$price' ] }
        }
      },
      {
        $group: {
          _id: null, // 使用null表示不需要分组，直接累加所有文档
          amount: { $sum: '$totalPrice' } // 对totalPrice字段进行累加
        }
      }
    ]);
    const count = countRes.length > 0 ? countRes[0].count : 0;
    const amount = assessRes.length > 0 ? assessRes[0].amount : 0;
    console.log('assess res', assessRes);
    return { status: 'ok', result: { list, count, amount } };
  }

  async createOrUpdateShippingFee(body) {
    const { ctx } = this;
    const { materials = [] } = body;
    _.map(materials, async item => {
      const { shippingFee = 0, pmLotId } = item;
      item.orderCode = body.code;
      item.createdType = '采购物料运费';
      item.deliverChannel = '采购单';

      const { price = 0 } = item;
      item.price = price;
      //  item.pmLotId='PML'+moment().format('YYYY-MM-DD-HHmmss');
      delete item._id;
      delete item.createdAt;
      delete item.createdTs;
      const res = await ctx.app.dbs.findOne('ShippingFee', { pmLotId });
      if (res) {
        const result = await ctx.app.dbs.updateOne('ShippingFee', { pmLotId }, item);
      } else {
        item.code = 'SPF' + Date.now()
          .valueOf();
        const result = await ctx.app.dbs.insert('ShippingFee', item);
      }
    });
    return true;
  }

  async updateSalesOrderMaterial(newMaterial) {
    const { ctx } = this;
    const { price } = newMaterial;
    const arr = await ctx.app.dbs.find('SalesOrder', { 'prods.materials.pmLotId': newMaterial.pmLotId });
    _.map(arr, async order => {
      const { prods = [] } = order;
      let mainCost = 0;
      _.map(prods, p => {
        const { materials } = p;
        const _materials = [];
        _.map(materials, (oldMaterial, index) => {
          const { pmLotId } = oldMaterial;
          if (pmLotId === newMaterial.pmLotId) {
            _.merge(oldMaterial, newMaterial);
            const { materialCount = 0 } = oldMaterial;
            console.log('main cost count', index, materialCount, price);
            mainCost += materialCount * price;
          }
          _materials.push(oldMaterial);
        });
        p.materials = _materials;
      });
      console.log('main cost', order.prods[0].materials);
      order.mainCost = mainCost;
      const arr = await ctx.app.dbs.updateOne('SalesOrder', { code: order.code }, order);
    });
  }


  /**
   * 创建物料
   * @param body
   * @returns {Promise<{status: string, result: *}>}
   */
  async createMaterial(body) {
    const { ctx } = this;
    body.useCount = 0;
    const { price = 0 } = body;
    body.price = price;
    const result = await ctx.app.dbs.insert('ProcureMaterialRecord', body);
    return { status: 'ok', result };
  }

  /**
   * 查询占用物料的订单
   * @param body
   * @returns {Promise<{status: string, result: *}>}
   */
  async findProcureMaterialUseSalesOrder(body) {
    const { ctx } = this;
    const { pmLotId, tenantCode } = body;
    const result = await ctx.app.dbs.find('SalesOrder', { 'prods.materials.pmLotId': pmLotId });
    return { status: 'ok', result };
  }

  async findProcureMaterialLot(body) {
    const { ctx } = this;
    const { pmLotId, tenantCode } = body;
    const result = await ctx.app.dbs.findOne('ProcureMaterialRecord', { pmLotId, tenantCode });
    //  console.log('findProcureMaterialLot result', result);
    return { status: 'ok', result };
  }

  async findUsedProcureMaterials(body) {
    const { ctx } = this;
    console.log('findUseMaterials procure', body);
    const { tenantCode } = body;

    const result = await ctx.app.dbs.aggregate('ProcureMaterialRecord', [ {
      $match: {
        tenantCode,
        '$expr': { $lt: [ '$useCount', '$count' ] }//查找占用数量小于采购数量的
      }
    }, {
      $group: {
        _id: '$code', // 分组依据字段
        name: { $first: '$name' },
        code: { $first: '$code' },
        subcategory: { $first: '$subcategory' },
        spec: { $first: '$spec' },
        type: { $first: '$type' },
        number: { $first: '$number' }
      }
    } ]);
    return { status: 'ok', result };
  }

  /**
   * 查找可用物料批次信息
   * @param body
   * @returns {Promise<{status: string, result: *}>}
   */
  async findUsedProcureMaterialLots(body) {
    const { ctx } = this;

    const { tenantCode, code } = body;
    /**
     * 查找采购物料
     */
    const result = await ctx.app.dbs.find('ProcureMaterialRecord', {
      tenantCode, code,
      '$expr': { $lt: [ '$useCount', '$count' ] }//查找占用数量小于采购数量的
    });

    return { status: 'ok', result };
  }

  /**
   * 查询采购物料记录
   * @param body
   * @returns {Promise<{status: string, result: *}>}
   */

  async findProcureMaterialRecordMany(body) {
    const { ctx } = this;
    const { vendor, code, name, createdTs, spec, number, subcategory, checkInbound = false } = body;

    if (createdTs && createdTs.length > 0) {
      body['createdTs'] = {
        $gte: new Date(moment(createdTs[0])
          .valueOf()),
        $lt: new Date(moment(createdTs[1])
          .valueOf())
      };
    }
    const sort = {};
    sort[createdTs] = -1;
    if (vendor) body['vendor'] = { $regex: vendor };
    if (code) body['code'] = { $regex: code };
    if (subcategory) body['subcategory'] = { $regex: subcategory };
    if (spec) body['spec'] = { $regex: spec };
    if (number) body['number'] = { $regex: number };
    if (name) body['name'] = { $regex: name };
    if (checkInbound) body['inboundCount'] = { $gt: 0 };
    delete body['checkInbound'];
    const result = await ctx.app.dbs.aggregate('ProcureMaterialRecord', [
      { $match: { ...body } },
      { $sort: { ...sort } },
    ]);
    return { status: 'ok', result };
  }

  /**
   * 采购物料统计
   * @param body
   * @returns {Promise<{status: string, result: {amount: number, count: number, orders: *}}>}
   */
  async procureMaterialLotAssess(body) {
    const { ctx } = this;
    const { vendor, code, name, createdTs, spec, number, subcategory } = body;

    if (createdTs && createdTs.length > 0) {
      body['createdTs'] = {
        $gte: new Date(moment(createdTs[0])
          .valueOf()),
        $lt: new Date(moment(createdTs[1])
          .valueOf())
      };
    }
    const sort = {};
    sort[createdTs] = -1;
    if (vendor) body['vendor'] = { $regex: vendor };
    if (code) body['code'] = { $regex: code };
    if (subcategory) body['subcategory'] = { $regex: subcategory };
    if (spec) body['spec'] = { $regex: spec };
    if (number) body['number'] = { $regex: number };
    if (name) body['name'] = { $regex: name };
    const orders = await ctx.app.dbs.aggregate('ProcureMaterialRecord', [
      { $match: { ...body } },

    ]);

    let amount = 0,
      _count = 0,
      _useCount = 0,
      useAmount = 0,
      _inboundCount = 0,
      inboundAmount = 0;
    _.map(orders, item => {
      const { count = 0, price = 0, useCount = 0, inboundCount = 0 } = item;
      amount += count * price;
      _count += count;
      _useCount += useCount;
      useAmount += useCount * price;
      _inboundCount += inboundCount;
      inboundAmount += inboundCount * price;
    });
    const result = [
      { title: '总采购数量', value: _count },
      { title: '总采购金额', value: amount },
      // { title: '总占用数量', value: _useCount },
      // { title: '总占用金额', value: useAmount },
      // { title: '总入库数量', value: _inboundCount },
      // { title: '总入库金额', value: inboundAmount },
    ];
    return { status: 'ok', result };
  }


  async createInboundOrder(body) {
    const { ctx } = this;
    const { tenantCode, code } = body;
    const order = await ctx.app.dbs.findOne(table, { tenantCode, code });
    const order1 = await ctx.app.dbs.findOne('InboundOrder', { tenantCode, orderCode: code });
    if (order1) return { status: 'ok', result: order1 };
    order.orderCode = code;
    order.code = _stringUtils.getCode('INB');
    delete order['_id'];
    const result = await ctx.app.dbs.insert('InboundOrder', order);
    return { status: 'ok', result };
  }

  async exportExcel(body) {
    const { ctx } = this;
    const res = await this.findMany(body);
    console.log('find many', res);
    const { result } = res;
    const mod = ctx.model['ProcureOrder'];
    const _header = mod.schema.obj;
    delete _header['tenantName'];
    delete _header['tenantCode'];
    delete _header['createUser'];
    delete _header['createUsername'];
    delete _header['isDeleted'];
    delete _header['isEnabled'];
    delete _header['materialBody'];
    delete _header['labels'];
    const header = [];
    _.map(_header, (item, key) => {
      item.title = item.desc;
      item.dataIndex = key;
      item.key = key;
      header.push(item);
    });
    return { status: 'ok', result: { header, data: result } };
  }
};
